// src/utils/dagreUniversalLayoutUtils.ts
import dagre from 'dagre';
// Import NEW types
import type { UniversalFlowNode, UniversalFlowEdge } from '@/models/universalFlow';
import type { DagreRankdir } from '@/models/settings';
// Import the types for align and ranker from the store
import type { DagreAlign, DagreRanker } from '../stores/universalVisualizerSettingsStore';

/**
 * Applies layout using Dagre algorithm.
 * Filters hidden nodes *before* layout calculation.
 *
 * @param allNodes All universal flow nodes.
 * @param allEdges All universal flow edges.
 * @param rankdir Layout direction ('TB' or 'LR').
 * @param nodesep Node separation distance.
 * @param ranksep Rank (level) separation distance.
 * @param align Node alignment within rank (optional).
 * @param ranker Rank assignment algorithm (optional).
 * @returns An object with the *layouted* visible universal nodes and edges.
 */
export function calculateDagreLayout(
    allNodes: UniversalFlowNode[],
    allEdges: UniversalFlowEdge[],
    rankdir: 'TB' | 'LR' = 'TB',
    nodesep: number = 80,
    ranksep: number = 100,
    align: DagreAlign = undefined,
    ranker: DagreRanker = 'network-simplex'
): { nodes: UniversalFlowNode[]; edges: UniversalFlowEdge[] } {
    console.log(`[calculateDagreLayout] Executing with ${allNodes.length} nodes, ${allEdges.length} edges. Options:`, { rankdir, nodesep, ranksep, align, ranker });

    const visibleNodes = allNodes.filter(n => !n.hidden);
    const visibleNodeIds = new Set(visibleNodes.map(n => n.id));

    const layoutEdges = allEdges.filter(e =>
        visibleNodeIds.has(e.source) && visibleNodeIds.has(e.target)
    );

    if (visibleNodes.length === 0) {
        console.log("[calculateDagreLayout] No visible nodes to layout.");
        return { nodes: [], edges: [] };
    }

    const dagreGraph = new dagre.graphlib.Graph();
    dagreGraph.setDefaultEdgeLabel(() => ({}));
    dagreGraph.setGraph({
        rankdir: rankdir,
        nodesep: nodesep,
        ranksep: ranksep,
        align: align,
        ranker: ranker
    });

    const defaultNodeWidth = 216;
    const defaultNodeHeight = 80;

    visibleNodes.forEach(node => {
        const width = node.width || defaultNodeWidth;
        const height = node.height || defaultNodeHeight;
        dagreGraph.setNode(node.id, { width, height });
    });

    layoutEdges.forEach(edge => {
        dagreGraph.setEdge(edge.source, edge.target);
    });

    try {
        dagre.layout(dagreGraph);
        console.log("[calculateDagreLayout] Dagre layout calculation complete.");
    } catch (layoutError: any) {
        console.error("[calculateDagreLayout] Layout calculation failed:", layoutError);
        return { nodes: visibleNodes, edges: layoutEdges };
    }

    visibleNodes.forEach(node => {
        const dagreNode = dagreGraph.node(node.id);
        if (dagreNode) {
            node.position = {
                x: dagreNode.x - (dagreNode.width / 2),
                y: dagreNode.y - (dagreNode.height / 2)
            };
        } else {
            console.warn(`[calculateDagreLayout] Node ${node.id} not found in Dagre graph after layout.`);
        }
    });

    console.log(`[calculateDagreLayout] Returning ${visibleNodes.length} layouted nodes and ${layoutEdges.length} edges.`);
    return { nodes: visibleNodes, edges: layoutEdges };
}